﻿using System;
using GeoAPI.Geometries;

namespace YJKGridTopologyCal.Operation.Predicate
{
	public class RectangleContains
	{
		public static bool Contains(IPolygon rectangle, IGeometry b)
		{
			return new RectangleContains(rectangle).Contains(b);
		}

		public RectangleContains(IPolygon rectangle)
		{
			this.rectangle = rectangle;
			this.rectEnv = rectangle.EnvelopeInternal;
		}

		public bool Contains(IGeometry geom)
		{
			return this.rectEnv.Contains(geom.EnvelopeInternal) && !this.IsContainedInBoundary(geom);
		}

		private bool IsContainedInBoundary(IGeometry geom)
		{
			if (geom is IPolygon)
			{
				return false;
			}
			if (geom is IPoint)
			{
				return this.IsPointContainedInBoundary((IPoint)geom);
			}
			if (geom is ILineString)
			{
				return this.IsLineStringContainedInBoundary((ILineString)geom);
			}
			for (int i = 0; i < geom.NumGeometries; i++)
			{
				IGeometry geometryN = geom.GetGeometryN(i);
				if (!this.IsContainedInBoundary(geometryN))
				{
					return false;
				}
			}
			return true;
		}

		private bool IsPointContainedInBoundary(IPoint point)
		{
			return this.IsPointContainedInBoundary(point.Coordinate);
		}

		private bool IsPointContainedInBoundary(Coordinate pt)
		{
			return pt.X == this.rectEnv.MinX || pt.X == this.rectEnv.MaxX || pt.Y == this.rectEnv.MinY || pt.Y == this.rectEnv.MaxY;
		}

		private bool IsLineStringContainedInBoundary(ILineString line)
		{
			ICoordinateSequence coordinateSequence = line.CoordinateSequence;
			Coordinate coordinate = new Coordinate();
			Coordinate coordinate2 = new Coordinate();
			for (int i = 0; i < coordinateSequence.Count - 1; i++)
			{
				coordinateSequence.GetCoordinate(i, coordinate);
				coordinateSequence.GetCoordinate(i + 1, coordinate2);
				if (!this.IsLineSegmentContainedInBoundary(coordinate, coordinate2))
				{
					return false;
				}
			}
			return true;
		}

		private bool IsLineSegmentContainedInBoundary(Coordinate p0, Coordinate p1)
		{
			if (p0.Equals(p1))
			{
				return this.IsPointContainedInBoundary(p0);
			}
			if (p0.X == p1.X)
			{
				if (p0.X == this.rectEnv.MinX || p0.X == this.rectEnv.MaxX)
				{
					return true;
				}
			}
			else if (p0.Y == p1.Y && (p0.Y == this.rectEnv.MinY || p0.Y == this.rectEnv.MaxY))
			{
				return true;
			}
			return false;
		}

		private IPolygon rectangle;

		private readonly Envelope rectEnv;
	}
}
